package app

import (
	"context"
	"fmt"
	"gitee.com/zhucheer/orange/cfg"
	"gitee.com/zhucheer/orange/database"
	"gitee.com/zhucheer/orange/encrypt"
	"gitee.com/zhucheer/orange/logger"
	orangerequest "gitee.com/zhucheer/orange/request"
	"gitee.com/zhucheer/orange/utils"
	"net/http"
	"os"
	"strings"
	"time"
)

// AppSrv 应用注册接口
type AppSrv interface {
	ServeMux()
	Register()
}

// 启动应用
func AppStart(appSrv AppSrv) {
	consoleWelCome()

	// 加载配置文件
	cfg.ParseParams()
	cfg.StartConfig()

	// 启动logger
	logger.NewLogger()
	// 注册session
	sessionInit()
	// 注册路由
	appSrv.ServeMux()

	// 注册 数据库
	database.NewMysql().RegisterAll()
	database.NewRedis().RegisterAll()
	database.NewMongo().RegisterAll()
	database.NewPostgre().RegisterAll()

	//业务服务注册
	appSrv.Register()

	// http请求组件
	initRequest()

	// 启动http服务
	startHttpSrv()
}

// startHttpSrv 启动http服务
func startHttpSrv() {
	appAddr := cfg.GetString("app.httpAddr", cfg.ConfigDef.GetString("app.httpAddr"))
	appPort := cfg.GetInt("app.httpPort", cfg.ConfigDef.GetInt("app.httpPort"))
	pprofOpen := cfg.GetBool("app.pprofOpen", cfg.ConfigDef.GetBool("app.pprofOpen"))
	flagPort := cfg.GetIntFlag("port")
	if flagPort > 0 {
		appPort = flagPort
	}

	bindAddr := fmt.Sprintf("%s:%d", appAddr, appPort)
	httpApiMux := http.NewServeMux()
	faviconFunc(httpApiMux)
	if pprofOpen == true {
		runPprof(httpApiMux)
	}

	httpApiMux.HandleFunc("/", routerPatten)
	fmt.Println(fmt.Sprintf("[ORANGE] \033[0;33m start http server bind:%v, pid:%d\033[0m ", bindAddr, os.Getpid()))

	for _, item := range httpHandlerList {
		if item.patten != "" && item.patten != "/" {
			httpApiMux.Handle(item.patten, item.handler)
			consoleMsg("[CustomHttpHandle] "+item.patten, 33)
		}
	}
	for _, item := range assetsHandlerList {
		if item.patten != "" && item.patten != "/" {
			httpApiMux.Handle(item.patten, item.handler)
			consoleMsg("[AssetsHttpHandle] "+item.patten, 33)
		}
	}
	server := &http.Server{
		Addr:    bindAddr,
		Handler: httpApiMux,
	}
	appSrv := NewSrv(server)

	go func() {
		err := appSrv.AppListenAndServe()
		fmt.Println(fmt.Sprintf("[ORANGE] \033[0;33m http server shutdown %v \033[0m ", err))
		logger.Critical("http server shutdown %v", err)
	}()
	listenShutDownSign(context.Background(), appSrv)

	fmt.Println(fmt.Sprintf("[ORANGE] \033[0;33m app server shutdown pid %d \033[0m ", os.Getpid()))
	logger.Critical("app server shutdown pid %d", os.Getpid())
	time.Sleep(1 * time.Second)
	logger.LogCloseAll()
}

// getAppKey 获取应用密钥
func getAppKey() string {
	defaultKey := "orange is fast frame work"
	appKey := cfg.Config.GetString("app.key")
	if appKey == "" || len(appKey) < 8 {
		logger.Error("config app.key is empty or too short")
		appKey = defaultKey
	}
	appKeyMd5 := encrypt.Md5ToLower(appKey)
	return appKeyMd5
}

// routerPatten 路由接管
func routerPatten(w http.ResponseWriter, r *http.Request) {
	requestPath := strings.TrimRight(getPath(r), "/")
	if requestPath == "" {
		requestPath = "/"
	}
	method := r.Method

	ctx := NewCtx(context.Background(), w, r)
	ctx.session = sessioinStart(w, r)
	ctx.responseBody.Reset()
	ctx.OrangeInput = orangerequest.NewInput(r, maxBodySize)
	runTime := time.Now()

	defer httpAfterDo(ctx, runTime)

	httpHandler, httpMiddleware := routers.Find(method, requestPath, ctx)
	routerHandlerFunc(httpHandler, httpMiddleware, ctx)

	return
}

// 处理HTTP controller
func routerHandlerFunc(httpHandler HandlerFunc, middlewares []MiddleWare, ctx *Context) {
	routeFuncDo := func() HandlerFunc {
		if httpHandler != nil {
			return httpHandler
		}
		return NotFoundHandler
	}

	// 中间件依次调用
	var middleHandlerFunc = routeFuncDo()
	if middlewares != nil && len(middlewares) > 0 {
		for _, item := range middlewares {
			middleFunc := item.Func()
			middleHandlerFunc = middleFunc(middleHandlerFunc)
		}
	}

	if cfg.GetBool("app.csrfVerify", cfg.ConfigDef.GetBool("app.csrfVerify")) == true {
		ctx.CsrfToken = startCsrfToken(ctx.Session())
		middleHandlerFunc = checkCsrfToken(middleHandlerFunc)
	}

	middleHandlerFunc(ctx)
}

// httpAfterDo http后置操作
func httpAfterDo(c *Context, runTime time.Time) error {

	if err := c.session.SessionRelease(c.response); err != nil {
		logger.Error("session release error:%v", err)
	}

	if c.redirect != "" {
		http.Redirect(c.response, c.request, c.redirect, http.StatusFound)
		return nil
	}

	if c.responseStatus > 0 {
		c.response.WriteHeader(c.responseStatus)
	}
	// 最后输出body
	c.response.Write(c.responseBody.Bytes())

	// 异步执行后置操作
	for _, itemFunc := range c.afterDelayDoFuncs {
		go func(item afterDelayFunc) {
			time.Sleep(item.delay)
			item.doFunc(c)
		}(itemFunc)
	}
	c.ms = time.Since(runTime)

	//c.responseBody.Reset()
	return nil
}

// 输出已注册路由方法到控制台
func consoleRouter(method, patten string) {
	spaceLen := 7 - len(method)
	space := "       "
	space = space[:spaceLen]
	fmt.Println(fmt.Sprintf("[ORANGE] \033[0;33m %s\033[0m%s %s", method, space, patten))
}

// 输出提示到控制台
func consoleMsg(method string, colorNum int) {
	fmt.Println(fmt.Sprintf("[ORANGE] \033[0;%dm %s\033[0m\t ", colorNum, method))
}

// 输出已注册路由方法到控制台
func consoleWelCome() {
	console := `
//////////////////////////////////////////
  _____                               
 / ___ \                              
| |   | | ____ ____ ____   ____  ____ 
| |   | |/ ___) _  |  _ \ / _  |/ _  )
| |___| | |  ( ( | | | | ( ( | ( (/ / 
 \_____/|_|   \_||_|_| |_|\_|| |\____)
                         (_____|  
///////////////////////////////////////////
///////     Fast Api Web Framework     ////
/////// gitee.com/zhucheer/orange v0.2 ////
///////////////////////////////////////////

`
	fmt.Println(fmt.Sprintf("\033[0;33m %v \033[0m", console))
}

// faviconFunc 渲染favicon
func faviconFunc(httpSrv *http.ServeMux) {
	if hideIcon := cfg.GetBool("app.hideIcon", false); hideIcon {
		return
	}

	httpSrv.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "image/x-icon")
		w.Write(utils.GetFaviconByte())
	})
}
